package top.wutunan.util;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * @Description
 * @Author wutunan
 * @Date 2024/5/5
 */
public class ProxyCustom {


    /**
     * 创建动态代理对象
     * @param infce
     * @param handler
     * @return
     */
    public static Object createProxy(Class infce, CInvocationHandler handler) {
        //方法的字符串
        String methodStr = "";
        //换行+一个tab
        String rt = "\r\n";
        String tab = "\t";
        String r = "\n";
        //获取接口当中的所有方法，方便后面遍历方法构建代理类的字符
        Method[] methods = infce.getMethods();
        //每个方法的返回类型
        String rtype = "";
        //表示该方法有几个参数
        int args = 0;
        for (Method m : methods) {
            // mname(String p0, String p1)
            String argsStr = "";
            String argsValueStr = "";
            // 得当当前方法参数的个数
            int parametercount = m.getParameterCount();
            Class[] classesParamArr = null;
            String getMethodParamStr = "new class[]{";
            if (parametercount > 0) {
                classesParamArr = new Class[parametercount];
                // 得到参数的类型、和个数。
                Class<?>[] parameterTypes = m.getParameterTypes();
                int pc = 0;
                for (Class<?> parameterType : parameterTypes) {
                    //classesParamArr[pc]=parameterType;
                    getMethodParamStr += parameterType.getSimpleName() + ".class,";
                    argsStr += parameterType.getSimpleName() + " p" + pc + ",";
                    argsValueStr += "p" + pc + ",";
                    pc++;
                }
                // 截取最后一个逗号
                getMethodParamStr = getMethodParamStr.substring(0, getMethodParamStr.length() - 1);
                argsStr = argsStr.substring(0, argsStr.length() - 1);
                argsValueStr = argsValueStr.substring(0, argsValueStr.length() - 1);

            }
            getMethodParamStr += "}";
            rtype = m.getReturnType().getSimpleName();
            boolean flag = false;
            String endReturnStr = "";
            String returnStr = "";
            if (!rtype.equals("void")) {
                // 返回的类型不是void
                returnStr = "return";
                endReturnStr = "return null;";
                flag = true;
            }

            String convertStr = "";
            if (flag) {
                convertStr = "(" + rtype + ")";
            }
            // 没有参数
            methodStr += tab + "@0verride" + rt +
                    tab + "public " + rtype + " " + m.getName() + "(" + argsStr + "){" + rt +
                    tab + tab + "try{" + rt +
                    tab + tab + tab + "Method md =" + infce.getSimpleName() + ".class.getMethod(\"" + m.getName() + "\"," + getMethodParamStr + ");" + rt +
                    //
                    tab + tab + tab + returnStr + " h.invoke(this, md, new 0bject[]{" + argsValueStr + "}).tostring();" + rt +
                    tab + tab + "}catch(Exception e){" + rt +
                    tab + tab + tab + "e.printStackTrace();" + r + tab + tab + "}" + r +
                    tab + tab + "return null;" + r +
                    tab + "}";
        }
        String src =
                "package top.wutunan.util;" + rt +
                        "import java.lang.reflect.Method;" + rt +
                        "import " + infce.getName() + ";" + rt +
                        "import top.wutunan.util.CInvocationHandler;" + rt +
                        "public class $Proxy1 implements " + infce.getSimpleName() + "{" + rt +
                        "\tCInvocationHandler h;" + rt +
                        "\tpublic $Proxy1(cInvocationHandler h){" + rt +
                        "\t\tthis.h= h;" + rt +
                        "\t}" + rt +
                        methodStr +
                        "\n}";


        System.out.println(src);
        String fileName = "";
        // 输出到java文件中，IO
        File root = new File("E:\\java_code\\batis_poject\\design_pattern\\src\\main\\java\\top\\wutunan");
        if (!root.exists()) {
            root.mkdirs();
            fileName = "E:\\java_code\\batis_poject\\design_pattern\\src\\main\\java\\top\\wutunan\\$Proxy1.java";
            File f = new File(fileName);
            if (!f.exists()) {
                try {
                    f.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            FileWriter fw = null;
            try {
                fw = new FileWriter(f);
                fw.write(src);
                fw.flush();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


        //把]ava原文件编译成class文件
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileMgr.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
        t.call();
        try {
            fileMgr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //从磁盘或者网络上面加载一个类文件到IVM
        URL[] urls = new URL[0];
        try {
            urls = new URL[]{new URL("file:/d:/")};
            URLClassLoader ul = new URLClassLoader(urls);
            Class c = ul.loadClass("org.shadow.proxy.$Proxy1");
            Constructor declaredconstructor = c.getDeclaredConstructor(CInvocationHandler.class);
            Object proxy = declaredconstructor.newInstance(handler);
            return proxy;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}